/*

  支持多个input，或者form中多个input上传
  实验性功能，暂未使用
 */
const defaults = {
  url: '',
  name: '', // 上传文件的name，默认会获取input上面的name值
  data: {}, // 同时需上传的数据，目前只接受 序列化Array和Object
  auto: true, // 是否自动上传
  element: null, // input
  dragDrop: null, // 拖拽区域
  maxSize: '2M',
  accept: '', // 限制文件类型，默认获取element上的accept
  multiple: false, // 是否支持一次上传多个，可以写数字，2 => 代表最多上传2个
  partSize: 0, // 分片上传时每片的大小，默认是0，不分片上传
  partIndex: 0, // 分片上传时，开始上传的序号默认是第一片
  resend: false, // 断网造成的上传失败，是否在联网后自动上传

  init: $.noop, // 初始化完成后执行
  select: $.noop, // 选择文件后执行，监听change
  warning: $.noop, // 选择文件后，出现错误触发回调
  progress: $.noop, // 进度条回调 ,参数：(loaded,total)
  complete: $.noop, // 上传完成后回调
  success: $.noop, // 上传成功后回调 对于分片上传需要一个promise
  error: $.noop, // 上传失败后回调
};

class Plugin{
  constructor(element, options) {
    this.options = $.extend(defaults, options);
    this.element = element;
    this.upArray = [];
    this.uploading = false; // 是否正在上传
    this.build();
    this.options.init.call(this);
  }
  build(){
    if (this.element[0].tagName === 'FORM') {
      this.element = this.element.find(':file')
    }
    this.upArray = this.element.toArray().map(function(dom) {
      let name = 'plugin_' + pluginName;
      let plugin = $(dom).data(name);
      if (!plugin) {
        plugin = new Up({ ...this.options, element: $(dom) });
        $(dom).data(name, plugin);
      }
      return plugin;
    });
  }
  getUpInstance(name){ // 获取对应的input的实例
    let up = this.upArray[0];
    if (name) {
      index = this.upArray.find(v => v.inputName === name);
    }
    if (index > -1 && this.upArray[index]) {
      return this.upArray[index]
    }
    return null
  }
  getALLFiles() { // 获取所有实例里的file
    return this.upArray.reduce((arr, up) => {
      let fileArr = up.files.map(v => ({ name: up.inputName, file: v.file }));
      return [...arr, ...fileArr];
    });
  }
  remove(src, name) {
    let up = this.getUpInstance(name);
    up && up.remove(src);
  }
  reselect(src, name) {
    let up = this.getUpInstance(name);
    up && up.reselect(src);
  }
  upload(opt) {
    if (this.uploading) {
      this.warningHandling('uploading');
      return;
    }
    this.uploading = true;

    if (opt) { // 外部调用，可以传参
      this.options = { ...this.options, ...opt };
    }
    if (this.options.partSize > 0) { // 分片上传
      this.queueAjaxPart();
    } else {
      this.ajaxFile().then(() => this.uploading = false).catch(() => this.uploading = false);
    }
    return this;
  }
  async queueAjaxPart() {
    let arr = this.getUpFiles().map(v => {
      return () => this.ajaxPartFile(v.name, v.file);
    })
    for (let i = 0; i < arr.length; i++) {
      try{
        await this.arr[i]();
        if (i + 1 === arr.length) this.uploading = false; // 所有的都执行完再设为false
      }catch(e) {
        if (i + 1 === arr.length) this.uploading = false;
      }
    }
  }
  ajaxFile() {
    return new Promise((resolve, reject) => {
      const { options } = this;
      let resData = options.data;
      if (util.isObject(resData)) {
        resData = Object.keys(resData).map(v => ({ name: v, value: resData[v] }));
      }
      resData = [ ...resData, ...this.getUpFiles() ];

      util.request({
        url: options.url,
        data: resData,
        resend: options.resend,
        progress: options.progress,
        complete: options.complete(),
        success: (data) => {
          options.success(data);
          resolve(data);
        },
        error(xhr, status) {
          options.error(xhr, status);
          reject(xhr, status);
        },
      });
    });
  }
  ajaxPartFile(name, file) { // 分片上传
    return new Promise((resolve, reject) => {
      const { options } = this;
      const resData = {
        partSize: options.partSize,
        partIndex: options.partIndex,
        partTotalNum: 1,
        ...options.data,
      };

      function ajaxPart() {
        const { partSize, partIndex } = resData;
        const start = partIndex * partSize;
        const end = start + partSize;
        resData[name] = file.slice(start, end);
        resData.key = `${resData.key}_${partIndex}`;
        resData.partTotalNum = Math.ceil(file.size / partSize);

        util.ajax({
          url: options.url,
          data: resData,
          resend: options.resend,
          complete: options.complete,
          progress(num) {
            let per = ((num / 100) + partIndex + 1) * (100 / resData.partTotalNum);
            per = per.toFixed(2);
            options.progress(per > 99 ? 99 : per);
          },
          success: (result) => {
            options.success(result, { ...resData, defaultKey: options.data.key });
            if (partIndex + 1 < resData.partTotalNum) {
              resData.partIndex = partIndex + 1;
              ajaxPart();
            } else {
              resolve(result);
            }
          },
          error: (xhr, status) => {
            options.error(xhr, status);
            reject(xhr, status);
          },
        });
      }
      ajaxPart();
    });
  }
}
